package com.loopj.ohos.http.sample;

import com.loopj.ohos.http.AsyncHttpClient;
import com.loopj.ohos.http.AsyncHttpRequest;
import com.loopj.ohos.http.RequestHandle;
import com.loopj.ohos.http.ResponseHandlerInterface;
import com.loopj.ohos.http.ext.LocalHiLog;
import com.loopj.ohos.http.sample.ext.ColorHelper;
import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.HttpEntity;
import cz.msebera.android.httpclient.client.methods.HttpUriRequest;
import cz.msebera.android.httpclient.entity.StringEntity;
import cz.msebera.android.httpclient.impl.client.DefaultHttpClient;
import cz.msebera.android.httpclient.message.BasicHeader;
import cz.msebera.android.httpclient.protocol.HttpContext;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbColor;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.window.dialog.IDialog;
import ohos.agp.window.dialog.ListDialog;
import ohos.app.Context;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

/**
 * SampleParentAbility
 */
public abstract class SampleParentAbility extends Ability implements SampleInterface {
    /**
     * http
     */
    protected static final String PROTOCOL_HTTP = "http://";
    /**
     * http
     */
    protected static final String PROTOCOL_HTTPS = "https://";
    /**
     * http
     */
    protected static final int LIGHTGREEN = RgbPalette.parse("#FF00FF66");
    /**
     * http
     */
    protected static final int LIGHTRED = RgbPalette.parse("#FFFF3300");
    /**
     * http
     */
    protected static final int YELLOW = RgbPalette.parse("#FFFFFF00");
    /**
     * http
     */
    protected static final int LIGHTBLUE = RgbPalette.parse("#FF99CCFF");
    private static final String LOG_TAG = "SampleParentActivity";
    private static final int MENU_USE_HTTPS = 0;
    private static final int MENU_CLEAR_VIEW = 1;
    private static final int MENU_LOGGING_VERBOSITY = 2;
    private static final int MENU_ENABLE_LOGGING = 3;
    /**
     * PROTOCOL_HTTPS
     */
    protected static String PROTOCOL = PROTOCOL_HTTPS;
    private final List<RequestHandle> requestHandles = new LinkedList<RequestHandle>();
    /**
     * http
     */
    public DirectionalLayout customFieldsLayout;

    private AsyncHttpClient asyncHttpClient = new AsyncHttpClient() {

        @Override
        protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {
            AsyncHttpRequest httpRequest = getHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
            return httpRequest == null
                    ? super.newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context)
                    : httpRequest;
        }
    };
    private TextField urlEditText;
    private TextField headersEditText;
    private TextField  bodyEditText;
    /**
     * ClickedListener
     */
    protected final Component.ClickedListener onClickListener = new Component.ClickedListener() {
        @Override
        public void onClick(Component component) {
            final int id = component.getId();
            if(id == ResourceTable.Id_button_run) {
                try {
                    onRunButtonPressed();
                } catch (IOException e) {
                    LocalHiLog.info(LOG_TAG, e.getMessage());
                }
            } else if(id == ResourceTable.Id_button_cancel) {
                onCancelButtonPressed();
            } else if(id == ResourceTable.Id_button_setting) {
                boolean visible = settingLayout.getVisibility() == Component.VISIBLE;
                settingLayout.setVisibility(visible ? Component.HIDE : Component.VISIBLE);
            } else if(id == ResourceTable.Id_button_clear_outputs) {
                clearOutputs();
            } else if(id == ResourceTable.Id_button_set_logging) {
                showLoggingVerbosityDialog();
            }
        }
    };
    private DirectionalLayout responseLayout;
    DirectionalLayout settingLayout;
    private boolean useHttps = true;
    private boolean enableLogging = true;

    /**
     * String
     *
     * @param tt String
     * @return String
     */
    protected static String throwableToString(Throwable tt) {
        if (tt == null){
            return null;
        }
        StringWriter sw = new StringWriter();
        tt.printStackTrace(new PrintWriter(sw));
        return sw.toString();
    }

    /**
     * getContrastColor
     *
     * @param color getContrastColor
     * @return getContrastColor
     */
    public static int getContrastColor(int color) {
        double yt = (299 * ColorHelper.red(color) + 587 * ColorHelper.green(color) + 114 * ColorHelper.blue(color)) / 1000;
        return yt >= 128 ? Color.BLACK.getValue() : Color.WHITE.getValue();
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        setUIContent(ResourceTable.Layout_ability_sample_parent);
        Text title = (Text) findComponentById(ResourceTable.Id_title);
        title.setText(getSampleTitle());
        urlEditText = (TextField) findComponentById(ResourceTable.Id_edit_url);
        headersEditText = (TextField) findComponentById(ResourceTable.Id_edit_headers);
        bodyEditText = (TextField) findComponentById(ResourceTable.Id_edit_body);
        customFieldsLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_layout_custom);
        Button runButton = (Button) findComponentById(ResourceTable.Id_button_run);
        Button cancelButton = (Button) findComponentById(ResourceTable.Id_button_cancel);
        Button settingButton = (Button) findComponentById(ResourceTable.Id_button_setting);
        settingLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_setting_layout);
        DirectionalLayout headersLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_layout_headers);
        DirectionalLayout bodyLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_layout_body);
        responseLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_layout_response);
        urlEditText.setText(getDefaultURL());
        headersEditText.setText(getDefaultHeaders());
        bodyLayout.setVisibility(isRequestBodyAllowed() ? Component.VISIBLE : Component.HIDE);
        headersLayout.setVisibility(isRequestHeadersAllowed() ? Component.VISIBLE : Component.HIDE);
        runButton.setClickable(true);
        runButton.setClickedListener(onClickListener);
        if (cancelButton != null) {
            if (isCancelButtonAllowed()) {
                cancelButton.setVisibility(Component.VISIBLE);
                cancelButton.setClickedListener(onClickListener);
            } else {
                cancelButton.setEnabled(false);
            }
        }
        settingButton.setClickable(true);
        settingButton.setClickedListener(onClickListener);
        rowLimit();
    }
    private void rowLimit(){
        Checkbox useHttpsButton = (Checkbox) findComponentById(ResourceTable.Id_button_use_https);
        Checkbox enableLoggingButton = (Checkbox) findComponentById(ResourceTable.Id_button_enable_logging);
        Button clearOutputsButton = (Button) findComponentById(ResourceTable.Id_button_clear_outputs);
        Button setLoggingButton = (Button) findComponentById(ResourceTable.Id_button_set_logging);
        clearOutputsButton.setClickable(true);
        clearOutputsButton.setClickedListener(onClickListener);
        setLoggingButton.setClickable(true);
        setLoggingButton.setClickedListener(onClickListener);
        useHttpsButton.setCheckedStateChangedListener(new AbsButton.CheckedStateChangedListener() {
            @Override
            public void onCheckedChanged(AbsButton absButton, boolean checked) {
                useHttps = checked;
                PROTOCOL = useHttps ? PROTOCOL_HTTPS : PROTOCOL_HTTP;
                urlEditText.setText(getDefaultURL());
            }
        });
        enableLoggingButton.setCheckedStateChangedListener(new AbsButton.CheckedStateChangedListener() {
            @Override
            public void onCheckedChanged(AbsButton absButton, boolean checked) {
                enableLogging = checked;
                getAsyncHttpClient().setLoggingEnabled(enableLogging);
            }
        });
    }

    @Override
    public AsyncHttpRequest getHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {
        return null;
    }

    @Override
    public List<RequestHandle> getRequestHandles() {
        return requestHandles;
    }

    @Override
    public void addRequestHandle(RequestHandle handle) {
        if (null != handle) {
            requestHandles.add(handle);
        }
    }

    private void showLoggingVerbosityDialog() {
        ListDialog listDialog = new ListDialog(this);
        listDialog.setTitleText("Set Logging Verbosity");
        listDialog.setSingleSelectItems(new String[]{
                        "VERBOSE",
                        "DEBUG",
                        "INFO",
                        "WARN",
                        "ERROR",
                        "WTF"
                }, getAsyncHttpClient().getLoggingLevel() - 2);
        listDialog.setOnSingleSelectListener(new IDialog.ClickedListener() {
            @Override
            public void onClick(IDialog dialog, int which) {
                getAsyncHttpClient().setLoggingLevel(which + 2);
                dialog.destroy();
            }
        });
        listDialog.setButton(IDialog.BUTTON2, "Cancel", null);
        listDialog.show();
    }

    @Override
    public void onRunButtonPressed() throws IOException {
        addRequestHandle(executeSample(getAsyncHttpClient(),
                getUrlText(getDefaultURL()),
                getRequestHeaders(),
                getRequestEntity(),
                getResponseHandler()));
    }

    @Override
    public void onCancelButtonPressed() {
        asyncHttpClient.cancelRequests(this, true);
    }

    /**
     * string
     *
     * @return string
     */
    public List<Header> getRequestHeadersList() {
        List<Header> headers = new ArrayList<Header>();
        String headersRaw = headersEditText.getText() == null ? null : headersEditText.getText().toString();

        if (headersRaw != null && headersRaw.length() > 3) {
            String[] lines = headersRaw.split("\\r?\\n");
            for (String line : lines) {
                try {
                    int equalSignPos = line.indexOf('=');
                    if (1 > equalSignPos) {
                        throw new IllegalArgumentException("Wrong header format, may be 'Key=Value' only");
                    }

                    String headerName = line.substring(0, equalSignPos).trim();
                    String headerValue = line.substring(1 + equalSignPos).trim();
                    LocalHiLog.info(LOG_TAG, String.format(Locale.US, "Added header: [%s:%s]", headerName, headerValue));

                    headers.add(new BasicHeader(headerName, headerValue));
                } catch (Throwable t) {
                    LocalHiLog.error(LOG_TAG, "Not a valid header line: " + line, t);
                }
            }
        }
        return headers;
    }

    @Override
    public Header[] getRequestHeaders() {
        List<Header> headers = getRequestHeadersList();
        return headers.toArray(new Header[headers.size()]);
    }

    @Override
    public HttpEntity getRequestEntity() {
        String bodyText;
        if (isRequestBodyAllowed() && (bodyText = getBodyText()) != null) {
            try {
                return new StringEntity(bodyText);
            } catch (UnsupportedEncodingException e) {
                LocalHiLog.error(LOG_TAG, "cannot create String entity", e);
            }
        }
        return null;
    }

    /**
     * getUrlText
     *
     * @return getUrlText
     */
    public String getUrlText() {
        return getUrlText(null);
    }

    /**
     * getUrlText
     *
     * @param defaultText getUrlText
     * @return getUrlText
     */
    public String getUrlText(String defaultText) {
        return urlEditText != null && urlEditText.getText() != null
                ? urlEditText.getText().toString()
                : defaultText;
    }

    /**
     * getBodyText
     *
     * @return getBodyText
     */
    public String getBodyText() {
        return getBodyText(null);
    }

    /**
     * getBodyText
     *
     * @param defaultText getBodyText
     * @return getBodyText
     */
    public String getBodyText(String defaultText) {
        return bodyEditText != null && bodyEditText.getText() != null
                ? bodyEditText.getText().toString()
                : defaultText;
    }

    /**
     * getHeadersText
     *
     * @return getHeadersText
     */
    public String getHeadersText() {
        return getHeadersText(null);
    }

    /**
     * getHeadersText
     *
     * @param defaultText getHeadersText
     * @return getHeadersText
     */
    public String getHeadersText(String defaultText) {
        return headersEditText != null && headersEditText.getText() != null
                ? headersEditText.getText().toString()
                : defaultText;
    }

    /**
     * debugHeaders
     *
     * @param TAG debugHeaders
     * @param headers debugHeaders
     */
    protected final void debugHeaders(String TAG, Header[] headers) {
        if (headers != null) {
            LocalHiLog.info(TAG, "Return Headers:");
            StringBuilder builder = new StringBuilder();
            for (Header hh : headers) {
                String hb = String.format(Locale.US, "%s : %s", hh.getName(), hh.getValue());
                LocalHiLog.info(TAG, hb);
                builder.append(hb);
                builder.append("-");
            }
            addView(getColoredView(YELLOW, builder.toString()));
        }
    }

    /**
     * string
     *
     * @param TAG string
     * @param tt string
     */
    protected final void debugThrowable(String TAG, Throwable tt) {
        if (tt != null) {
            LocalHiLog.error(TAG, "AsyncHttpClient returned error", tt);
            addView(getColoredView(LIGHTRED, throwableToString(tt)));
        }
    }

    /**
     * string
     *
     * @param TAG string
     * @param response string
     */
    protected final void debugResponse(String TAG, String response) {
        if (response != null) {
            LocalHiLog.info(TAG, "Response data:");
            LocalHiLog.info(TAG, response);
            addView(getColoredView(LIGHTGREEN, response));
        }
    }

    /**
     * string
     *
     * @param TAG string
     * @param statusCode string
     */
    protected final void debugStatusCode(String TAG, int statusCode) {
        String msg = String.format(Locale.US, "Return Status Code: %d", statusCode);
        LocalHiLog.info(TAG, msg);
        addView(getColoredView(LIGHTBLUE, msg));
    }

    /**
     * string
     *
     * @param bgColor string
     * @param msg string
     * @return string
     */
    protected Component getColoredView(int bgColor, String msg) {
        Text tv = new Text(this);
        tv.setLayoutConfig(new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_CONTENT));
        tv.setText(msg);
        ShapeElement element = new ShapeElement();
        element.setRgbColor(RgbColor.fromArgbInt(bgColor));
        tv.setBackground(element);
        tv.setPadding(10, 10, 10, 10);
        tv.setTextColor(new Color(getContrastColor(bgColor)));
        tv.setMultipleLine(true);

        return tv;
    }

    @Override
    public String getDefaultHeaders() {
        return null;
    }

    /**
     * SynchronousClientSample
     *
     * @param vv SynchronousClientSample
     */
    protected final void addView(Component vv) {
        responseLayout.addComponent(vv);
    }

    /**
     * SynchronousClientSample
     */
    protected final void clearOutputs() {
        responseLayout.removeAllComponents();
        responseLayout.invalidate();
    }

    /**
     * SynchronousClientSample
     *
     * @return SynchronousClientSample
     */
    public boolean isCancelButtonAllowed() {
        return false;
    }

    /**
     * SynchronousClientSample
     *
     * @return SynchronousClientSample
     */
    public AsyncHttpClient getAsyncHttpClient() {
        return this.asyncHttpClient;
    }

    @Override
    public void setAsyncHttpClient(AsyncHttpClient client) {
        this.asyncHttpClient = client;
    }

}
